#include "tcp_receiver.hh"

#include <iostream>

// Dummy implementation of a TCP receiver

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

void TCPReceiver::segment_received(const TCPSegment &seg) {
    TCPHeader header = seg.header();
    // get necessary flag at first
    bool syn = header.syn;
    bool fin = header.fin;
    if (!syn && !_isn.has_value())
        return;
    if (syn && !_isn.has_value())
        _isn = header.seqno;

    if (_fin_got && fin)
        return;
    if (_isn.has_value() && fin && !_fin_got)
        _fin_got = true;

    // calculate index
    WrappingInt32 seqno = header.seqno;
    size_t next_to_assemble = _reassembler.next_to_assemble();
    size_t index = unwrap(seqno, _isn.value(), next_to_assemble);
    size_t sindex = index - (_isn.has_value() && !syn ? 1 : 0);

    // extract data
    std::string_view payload = seg.payload();
    std::string data(payload);
    _reassembler.push_substring(data, sindex, fin);
}

optional<WrappingInt32> TCPReceiver::ackno() const {
    if (_isn.has_value()) {
        return wrap(_reassembler.next_to_assemble() + 1 + (_reassembler.empty() && _fin_got ? 1 : 0), _isn.value());
    }
    return {};
}

size_t TCPReceiver::window_size() const {
    size_t sw_idx = _reassembler.stream_out().bytes_read();
    size_t assembled = _reassembler.next_to_assemble() - sw_idx;
    // size_t unassembled= _reassembler.unassembled_bytes();
    return _capacity - assembled;
}
